package com.cyou.qb.service.impl;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cyou.fz173.util.JacksonUtil;
import com.cyou.nad.mongo.orm.core.MongoDBTemplate;
import com.cyou.nad.utils.DateUtils;
import com.cyou.nad.utils.cache.MyMemCache;
import com.cyou.qb.common.dao.JiuGongGeDao;
import com.cyou.qb.common.domain.Active;
import com.cyou.qb.common.domain.ActiveRule;
import com.cyou.qb.common.domain.AssignedWinner;
import com.cyou.qb.common.domain.Award;
import com.cyou.qb.common.domain.AwardDetail;
import com.cyou.qb.common.domain.BlackList;
import com.cyou.qb.common.domain.JiuGongGe;
import com.cyou.qb.common.domain.Winner;
import com.cyou.qb.common.domain.vo.DrawAward;
import com.cyou.qb.common.domain.vo.OtherDrawAward;
import com.cyou.qb.common.domain.vo.VirtualDrawAward;
import com.cyou.qb.common.mongo.po.ClickLog;
import com.cyou.qb.common.mongo.po.DrawLog;
import com.cyou.qb.common.service.ActivityService;
import com.cyou.qb.common.service.AwardConfigChanceService;
import com.cyou.qb.common.service.AwardService;
import com.cyou.qb.common.service.BlackListService;
import com.cyou.qb.common.service.UserDrawTraceService;
import com.cyou.qb.common.service.WinnerService;
import com.cyou.qb.common.service.impl.BaseSerivceImpl;
import com.cyou.qb.service.DrawService;
import com.cyou.qb.constants.CacheKeyConstants;
import com.cyou.qb.constants.DBStoreConstants;
import com.cyou.qb.exception.DrawException;
import com.cyou.qb.exception.ServiceException;
import com.cyou.qb.face.exception.QbGetDataException;
import com.cyou.qb.face.service.PassportCheckService;
import com.cyou.qb.face.service.QbOperateService;
import com.cyou.qb.face.service.QbOperateService.MinusGbResult;

/**
 * <p>中奖逻辑</p>
 * @author zoudongchao<br>
 * 1. 传入参数校验，校验activeId和passport。若参数错误则抛出参数错误异常；<br>
 * 2. mongo记录点击日志（clicklog）<br>
 * 3. 判断是否有资格抽奖<br>
 * 		获取活动抽奖条件，形成抽奖条件列表（ruleList），遍历判断每一个抽奖条件<br>
 * 		3.1 if 资料完整度要求<br>
 * 				调用接口获取用户资料完整度，若资料完整度不足，则抛出资料完整度不足异常<br>
 * 		3.2 else if 联系信息完整度要求<br>
 * 				调用接口获取用户资料完整度，若不满足，则抛出联系信息完整度不足异常<br>
 * 		3.3 else if 级别要求<br>
 * 				调用接口获取用户级别，若用户级别不够，则抛出用户级别不够异常<br>
 * 		3.4 else if 抽奖需要消耗G币<br>
 * 				调用接口获取用户G币剩余，若剩余G币小于需要消耗G币数，则抛出G币不足异常<br>
 * 		3.5 else if 抽奖次数限制<br>
 * 				查询Cache获取该活动中当前用户的可用抽奖次数，若无可用抽奖次数，则抛出无抽奖次数异常<br>
 * 		3.6  其他<br>
 * 				抛出未知抽奖条件异常<br>
 * 		最终返回需要消耗的G币数，若无G币要求，则返回为0<br>
 * 
 * 4. 根据参与活动需要消耗的G币数，调用接口扣除用户G币<br>
 * 5. 更新Cache中活动参与人数（+1）<br>
 * 6. 更新Cache中用户已用抽奖次数（+1）<br>
 * 7. mongo记录抽奖日志(drawlog)<br>
 * 8. 判断用户是否是有效黑名单(处在封禁时间内)<br>
 * 		是，则返回直接返回空<br>
 * 
 * 
 * 9. 判断是否为指定用户中奖<br>
 * 		9.1根据活动id和通行证获取指定用户列表（可以指定多个奖品）<br>
 * 			对每一个指定用户记录，<br>
 * 				获取对应奖品id，判定该奖品是否配置在九宫格上<br>
 * 					是，并且还可以抽中（指定用户currNum>0），则返回对应奖品实体<br>
 * 			若最终没有找到可中奖品，则返回为空<br>
 * 		如果9.1最终返回为空，则直接返回空（<b>指定用户不再中其他奖品</b>）<br>
 * 		如果9.1返回对应奖品实体，则更新指定用户可抽奖次数，并将中奖信息存入库中，最终返回DrawAward实体<br>
 * 
 * 10. 获取该活动所有奖品列表,根据中奖尾数降序排列<br>
 * 		然后提取其中配置在九宫格上的奖品作为有效奖品列表<br>
 * 
 * 11. 时间中奖<br>
 * 		获取有效奖品列表中的时间中奖奖品<br>
 * 		11.1  对每一个时间中奖奖品<br>
 * 			获取奖品中奖时间点列表<br>
 * 			11.1.1 对每一个中奖时间点<br>
 * 				中奖时间点和相应奖品结对，依据时间先后形成一个中奖区间列表（<b>一个时间点允许有多个奖品</b>）<br>
 * 		11.2 判定所属中奖区间
 * 			11.2.1  若抽奖时间早于最早当日中奖时间点，跳出时间中奖判定，进入尾数中奖判定
 * 			11.2.2 找到所属中奖区间后，获得该时间点的所有时间中奖奖品
 * 			11.2.3 对每一个奖品，查询数据库，获得该时间区间内该奖品的中奖情况
 * 				11.2.3.1 若无人中奖，则该用户抽中，返回对应奖品实体
 * 				11.2.3.2 若多于一人中奖，则数据库存储错误（统一时间段内不应当有两个及以上中奖记录）
 * 		
 * 		若11.2返回为空，则进入尾数中奖判断
 * 		否则，判定是否有库存
 * 			若有，则中间信息入库，提示中奖
 * 			若无，则提示未中奖
 * 		
 * 12. 判断是否为尾数中奖<br>
 * 		传入用户抽奖尾数和奖品列表(按中奖尾数降序排列)
 * 		12.1 对每一个尾数中奖奖品		
 * 			判定用户抽奖尾数是否以奖品指定尾数结尾
 * 			是，则返回奖品实体
 * 		
 * 		若12.1返回非空，则中奖信息入库，提示中奖
 * 		否则，提示不中奖
 *	
 *	
 *	分布式jvm 抽奖冲突解决办法
 *	使用memcached cas 乐观锁解决
 *	在抽奖前，获取active对应的version
 *	如果没有抽到奖品，则不做特殊处理
 *	如果抽到了奖品
 *		在执行了数据库操作后，再次获取 active的版本号
 *		如果版本号没有变化，则表示没有冲突，操作是正常的，active版本号+1
 *		如果版本号有变化，表示冲突了，抛出异常，事务回滚。
 * 
 */

@Service("drawServiceImpl")
public class DrawServiceImpl extends BaseSerivceImpl implements DrawService {

	
	@Resource(name="ActivityServiceCacheImpl")
	private ActivityService activityService;

	@Resource(name="AwardServiceCacheImpl")
	private AwardService awardService;
	
	@Resource(name="WinnerServiceCacheImpl")
	private WinnerService winnerService;
	
	@Resource(name="AwardConfigChanceServiceCacheImpl")
	private AwardConfigChanceService awardConfigChanceService;
	
	@Resource(name="BlackListServiceCacheImpl")
	private BlackListService blackListService;
	
	@Autowired
	private UserDrawTraceService userDrawTraceService;
	
//	@Resource(name = "QbPassportMock")
	@Resource(name = "QbPassportImpl")
	private PassportCheckService passportCheckService;
	
	@Resource(name = "QbOperateImpl")
//	@Resource(name = "QbOperateMock")
	private QbOperateService qbOperateService;
	@Autowired
	private JiuGongGeDao jiuGongGeDao;
	
	@Autowired
	private MongoDBTemplate template = null;
	private static Logger logger = Logger.getLogger(DrawServiceImpl.class);
	
//	//测试冲突使用
//	private static int seqForDebug=0;
	
	private Object lock = new Object();
	
	@Override
	public DrawAward draw(int activeId, int uCenterId, String passport) throws DrawException, QbGetDataException, Exception {
		if (activeId < 0 || passport == null || passport.length() == 0) {
			logger.info("抽奖传入参数错误[activeId="+activeId+",uCenterId="+uCenterId+",passport="+passport+"]");
			throw new DrawException(DrawException.UNEXPECTED_PARAM,"抽奖传入参数错误[activeId="+activeId+",uCenterId="+uCenterId+",passport="+passport+"]");
		}
		
		//获取活动信息
		Active active = activityService.findActivity(activeId);
		if (active == null) {
			return null;
		}

		//抽奖时间
		Date drawTime = new Date();
		
		//记录抽奖点击信息
		ClickLog clog = new ClickLog(active.getId(), active.getActiveName(), uCenterId, passport, drawTime, new Date());
		template.save(clog);
		
		//判断是否能进行抽奖 返回G币消耗  
		//如果同一个passport高并发 ，此处存在不安全因素，但是考虑到同一个用户产生高并发的情况，只能是用户通过程序刷 抽奖，这种情况可以通过外部监控doc攻击处理掉
		int gCost = isAbleToDraw(uCenterId, passport, active);
		
		//更新抽奖尾数    预读Cache
		long tail = userDrawTraceService.findActiveDrawTimes(activeId);
		userDrawTraceService.updateActiveDrawTimesIncr(activeId);
//		long newTail = userDrawTraceService.findActiveDrawTimes(activeId);//做一步校验，防止Cache出错
//		tail = tail + 1;//当前用户尾数
//		if (tail != newTail) {
//			logger.error("更新抽奖尾数cache失败");
//			throw new ServiceException("更新抽奖尾数cache失败");
//		}
		
		//有资格抽奖 则已用抽奖次数加一
		userDrawTraceService.updateUserActiveDrawTimesIncr(uCenterId, activeId);
		
		//mongo写入抽奖信息
		DrawLog dlog = new DrawLog(active.getId(), active.getActiveName(), uCenterId, passport, gCost, drawTime, new Date());
		template.save(dlog);
		
		//黑名单判断		预读Cache
		List<BlackList> blackList = blackListService.findBlackList(passport, new Date());
		if (blackList != null && blackList.size() > 0) {
			logger.info("user in blacklist");
			return null;
		}
//		logger.info(" seq:"+seqForDebug);
		//获得乐观锁版本号
		long version = getLuckyLock(activeId);
//		logger.info("version:"+version+"\t seq:"+seqForDebug);
		Award result = null;
		//指定用户
		//是否为指定用户
		List<AssignedWinner> winnerList = awardConfigChanceService.findAssignedWinner(activeId, passport);
		if (winnerList != null && winnerList.size() > 0) {
			result = assignedDraw(winnerList);
			if (result == null) {
				return null;//  指定用户不再中其他的奖品
			}
			logger.debug("[draw]assigned user");
			logger.info("[draw]store draw info to db and give award to user...");
			//减少指定用户可中奖次数 currNum
			awardConfigChanceService.updateAssignedWinnerDrawTimes(result.getActiveId(), result.getId(), passport);
			return storeDrawResultToDB(active, result, uCenterId, passport, drawTime,version);
		}
		
		//获取所有奖品
		List<Award> allAwards = awardService.findAwards(activeId);
		List<Award> awardList = new ArrayList<Award>();
		
		for (Award award : allAwards) {
			List<JiuGongGe> positions = jiuGongGeDao.findJIuGongGeByAwardId(award.getId());
			if (positions != null && positions.size() > 0) {
				awardList.add(award);
			}
		}
		
		//时间中奖
		result = timeDraw(awardList, drawTime);
		if (result != null) {//是时间中奖
			if (result.getCurrNum() <= 0) {//没有库存
				logger.info("[draw]is time draw,but no storage");
				return null;
			}
			logger.info("[draw]store draw info to db and give award to user...");
			//减少库存
			result.setCurrNum(result.getCurrNum() - 1);
			return storeDrawResultToDB(active, result, uCenterId, passport, drawTime,version);
		}
		
		//尾数中奖  用户尾数为tail+1
		result = sequenceDraw(awardList, activeId, tail+1);
		if (result != null) {//是尾数中奖
			if(result.getCurrNum() <= 0) {
				logger.info("[draw]is sequence draw,but no storage");
				return null;
			}
			logger.info("[draw]store draw info to db and give award to user...");
			//减少库存
			result.setCurrNum(result.getCurrNum() - 1);
			return storeDrawResultToDB(active, result, uCenterId, passport, drawTime,version);
		}
		
		return null;
	}
	
	/**
	 * 创建乐观锁，返回锁version
	 * @param activeId
	 * @return
	 */
	private long getLuckyLock(int activeId) {
		int i=0;
		while(true&&i<2){
			long version= MyMemCache.getInstance().getVersion(CacheKeyConstants.DOMAIN_DRAW_LOCK,activeId+"");
			if(version==-1l){
				MyMemCache.getInstance().put(CacheKeyConstants.DOMAIN_DRAW_LOCK, activeId+"","lock");
			}else{
				return version;
			}
		}
		return 1;
	}
	public boolean cas(int activeId,long version){
		return MyMemCache.getInstance().cas(CacheKeyConstants.DOMAIN_DRAW_LOCK, activeId+"","lock", version);
	}
	private void incrLuckyLockVersion(int activeId) {
		MyMemCache.getInstance().put(CacheKeyConstants.DOMAIN_DRAW_LOCK, activeId+"","lock");
	}

	/**
	 * <p>是否能进行抽奖</p>
	 * @param uCenterId
	 * 			用户中心id
	 * @param passport
	 * 			通行证
	 * @param active
	 * 			活动实体 可获得活动ID等信息
	 * @return 
	 * 			抽奖需消耗金币数 或者为null
	 */
	@SuppressWarnings("unchecked")
	protected int isAbleToDraw(int uCenterId, String passport, Active active) throws DrawException, QbGetDataException {
		//中奖规则
		List<ActiveRule> ruleList = JacksonUtil.toCollection(active.getRule(), ArrayList.class, ActiveRule.class);
		if (ruleList == null)
			throw new DrawException(DrawException.NO_RULE, "活动没有抽奖条件");
		
		int gCost = 0;
		int integrity = 0;
		for (ActiveRule rule : ruleList) {
			String ruleStr = rule.getType();
			if (ruleStr.equals(DBStoreConstants.RULE_BASIC)) {
				integrity = passportCheckService.getUserInfoCompletion(uCenterId);
				if (integrity < rule.getValue()) {
					throw new DrawException(DrawException.BASIC_INFO_NOT_COMPLETE, "基本信息完整度不足");
				}
			} else if (ruleStr.equals(DBStoreConstants.RULE_CONTACT)) {
				integrity = passportCheckService.getContactCompletion(uCenterId);
				if (integrity < rule.getValue()) {
					throw new DrawException(DrawException.CONTACT_INFO_NOT_COMPLETE, "联系信息完整度不足");
				}
			} else if (ruleStr.equals(DBStoreConstants.RULE_LEVEL)) {
				integrity = passportCheckService.getUserLv(uCenterId, passport);
				if (integrity < rule.getValue()) {
					throw new DrawException(DrawException.NO_ENOUGH_LEVEL, "级别不够");
				}
			} else if (ruleStr.equals(DBStoreConstants.RULE_TIMES)) {
				integrity = userDrawTraceService.findUserActiveDrawTimes(uCenterId, active.getId());//用户已抽奖次数
				//rule.getValue()为活动允许抽奖的次数 
				if (integrity >= rule.getValue()) {
					throw new DrawException(DrawException.NO_ENOUGH_DRAW_TIMES, "抽奖次数用尽");
				}
			}else if (ruleStr.equals(DBStoreConstants.RULE_GCOST)) {
				gCost = rule.getValue();
				//FIXME
				MinusGbResult minusGb = qbOperateService.minusGb(passport, gCost, "cost "+gCost+" gb to draw", 12);
				if(MinusGbResult.NOTRNOUGH.equals(minusGb)){
					throw new DrawException(DrawException.NO_ENOUGH_GOLD, "G币不足");
				}
				if(MinusGbResult.FAIL.equals(minusGb)){
					throw new DrawException(DrawException.INTERFACE_173_FAIL, "接口通信出错");
				}
			}  else {
				throw new DrawException(DrawException.UNKNOWN_RULE_TYPE,"未知抽奖条件");
			}
		}
		return gCost;
	}
	
	/**
	 * 判断指定用户中奖
	 * @param activeId	活动Id
	 * @param passport 用户通行证
	 * @return
	 */
	protected Award assignedDraw(List<AssignedWinner> winnerList) throws DrawException {
		//可以指定一个用户中多个奖品，顺序给出即可
		for (AssignedWinner winner : winnerList) {
			int awardId = winner.getAwardId();
			//判断九宫格
			List<JiuGongGe> positions = jiuGongGeDao.findJIuGongGeByAwardId(awardId);
			if (positions != null && positions.size() > 0 && winner.getCurrNum() > 0) {
				return awardService.findAward(awardId);
			}
			continue;
		}
		
		return null;
	}

	/**
	 * 时间中奖：
	 * 判断时间中奖方式的奖品在24点之前是否有人抽中
	 * 		若没有，则判断是否有库存，有，则中奖；没有，则进行尾数中奖判断
	 * 需查询奖品表和中奖名单表
	 * @param awardList	奖品列表
	 * @param drawTime 抽奖时间
	 */
	protected Award timeDraw(List<Award> awardList, Date drawTime) throws DrawException {
		//奖品列表为空，直接返回不中奖
		if (awardList != null && awardList.size() != 0) {
			List<Winner> winnerList = new ArrayList<Winner>();
			
			//生成时间区间
			Map<Date, List<Award>> timeZone = createTimeZone(awardList);
			if (timeZone == null || timeZone.isEmpty())
				return null;
			List<Map.Entry<Date, List<Award>>> list = new ArrayList<Map.Entry<Date, List<Award>>>(timeZone.entrySet());
			//早于最早时间点
			if (drawTime.before(list.get(0).getKey()))
				return null;
			
			for (Entry<Date, List<Award>> temp : list){
				List<Award> awards = temp.getValue();
				Date start = temp.getKey();
				Date end = null;
				//end
				if (list.indexOf(temp) + 1 == list.size()) {//最后一个时间点   则end为次日最早中奖时间点
					end = DateUtils.addDayWithTime(list.get(0).getKey(), 1);
				} else {
					end = list.get(list.indexOf(temp)+1).getKey();
				}
				//先判断时间区间
				if (drawTime.before(start) || drawTime.after(end) || drawTime.equals(end))
					continue;
				
				for (Award tempAward : awards) {
					//查找  
					winnerList = winnerService.findWinner(tempAward.getId(), tempAward.getActiveId(), start, end);
					if (winnerList.size() == 1) {//不中
						//不能直接返回
						if (awards.indexOf(tempAward) + 1 == awards.size())//最后一个
							return null;
						continue;
					}else if (winnerList.size() == 0) {
						return tempAward;//没人中奖，可以直接返回奖品
					}else {
						//同一时间段不应当有两个时间中奖纪录
						logger.error("[timeDraw]more than one record in t_winner");
						throw new DrawException(DrawException.DB_STORE_EXCEPTION, "[timeDraw]t_winner查询出多于一条记录");
					}
				}
			}
		}

		return null;
	}

	/**
	 * 尾数中奖：
	 * @param awardList 尾数中奖奖品列表，依<b>尾数降序排序<b>
	 */
	protected Award sequenceDraw(List<Award> awardList, int activeId, long tail) {

		if (awardList != null && awardList.size() != 0) {
			//cache获取活动抽奖次数
			String tailNum = Long.toString(tail);//Integer.toString(getUserDrawTailFromCache(uCenterId, activeId));
			for (Award award : awardList) {
				if (award.getWinType()!=DBStoreConstants.SEQUENCE_DRAW)
					continue;
				String numStr = Integer.toString(award.getNumWin());
				if (tailNum.endsWith(numStr))//尾数降序，找到第一个必然尾数最大 直接返回
					 return award;
			}
		}
		return null;
	}

	/**
	 * <p>中奖奖品分配</p>
	 * 实体和虚拟物品只需要库存减一<br/>
	 * G币和经验值减去相应的gNum，同时需要给用户添加G币和经验值
	 * @param award
	 * @param uCenterId
	 * @param passport
	 * @param drawTime
	 * @param version 
	 * @return
	 * @throws QbGetDataException
	 */
	protected DrawAward storeDrawResultToDB(Active active, Award award, int uCenterId, String passport, Date drawTime, long version)
			throws QbGetDataException,Exception {
		
		DrawAward result = null;
		
		//生成中奖名单 入库
		Winner winner = new Winner();
		winner.setActiveId(active.getId());
		winner.setAwardId(award.getId());
		winner.setuCenterId(uCenterId);
		winner.setPassport(passport);
		winner.setNickname(passportCheckService.getUserNickname(uCenterId));
		winner.setWinTime(drawTime);

		//虚拟奖品需要获得detailId
		if (award.getType().equals(DBStoreConstants.AWARD_VIRTUAL)) {
			AwardDetail awardDetail = null;
			awardDetail = awardService.findAwardDetail(award.getId());
			//考虑判空
			if (awardDetail == null)
				throw new ServiceException("未找到可用点卡");
			awardDetail.setUsed(1);
			awardService.updateOneAwardDetail(awardDetail);
			winner.setAwardDetailId(awardDetail.getId());//虚拟物品设置detailId
			result = new VirtualDrawAward(award, 0, awardDetail.getCardNo(), awardDetail.getCardPwd());
		//实体
		}else if (award.getType().equals(DBStoreConstants.AWARD_ENTITY)) {
			result = new DrawAward(award, 0);
		}
		//先写入本地库
		awardService.updateAwardCurrNum(award);//更新库存
		winnerService.saveOneWinner(winner);
		
		//此处故意产生冲突，第一个请求等待1m 第二个请求不需要等待  ,由于存在数据库事务，效果不是很明显
//		if(seqForDebug++%2==0){
//			Thread.currentThread().sleep(1000*60);
//		}
		//FIXME
		synchronized (lock) {
			//如果产生了奖品，就需要比较锁版本号，如果冲突，就回滚，如果不冲突，就增加版本号
			//乐观锁校验版本号
			long checkLock = getLuckyLock(active.getId().intValue());
			if (checkLock != version) {
				logger.error("抽奖线程产生冲突，系统自动回滚本次抽奖");
				throw new RuntimeException("抽奖线程产生冲突，系统自动回滚本次抽奖");
			}
			if(!cas(active.getId().intValue(), version)){
				logger.error("抽奖线程产生冲突，系统自动回滚本次抽奖");
				throw new RuntimeException("抽奖线程产生冲突，系统自动回滚本次抽奖");
			}
			//如果产生了奖品则版本号+1
			incrLuckyLockVersion(active.getId().intValue());
		}
		
		//经验值
		if (award.getType().equals(DBStoreConstants.AWARD_EXPERIENCE)) {
			passportCheckService.plusExperience(uCenterId, "plus Experience", award.getgNum(), passport);
			result = new OtherDrawAward(award, 0);
		//G币
		}else if (award.getType().equals(DBStoreConstants.AWARD_GOLD)) {
			qbOperateService.plusGb(passport, active.getFaceNum(), award.getgNum(), "win gb, plus "+award.getgNum());
			result = new OtherDrawAward(award, 0);
		}

		result.setWinnerId(winner.getId());//设置winnerId
		return result;
	}

	/**
	 * <p>创建中奖时间区间</p>
	 * 考虑同一时间点问题
	 * @param awardList 奖品列表，中奖尾数降序排列
	 * @return
	 */
	protected Map<Date, List<Award>> createTimeZone(List<Award> awardList) {
		Map<Date, List<Award>> timeZone = new TreeMap<Date, List<Award>>(new Comparator<Date>() {
			public int compare(Date date1, Date date2) {
				return date1.compareTo(date2);
			}
		});
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");

		Date day = new Date();
		String dayStr = format.format(day);//获取当前服务器日期

		for (Award award : awardList) {
			if (award.getWinType()!=DBStoreConstants.TIME_DRAW){
				continue;//跳过非时间中奖奖品
			}
			
			String dateWin = award.getDateWin();
			if (dateWin == null || dateWin.length() == 0)
				break;
			String[] times = dateWin.split(";");
			//分号分隔   不排除同一个奖品设置多个相同的时间点的可能性，需要合并
			for (String time : times) {
				//插入到list中
				Date date = new Date();
				try {
					date = org.apache.commons.lang.time.DateUtils.parseDate(dayStr + " " + time,new String[]{"yyyy-MM-dd HH:mm:ss","yyyy-MM-dd HH:mm","yyyy-MM-dd","yyyy-MM-dd HH"});
				} catch (ParseException e) {
					e.printStackTrace();
					logger.error("[createTimeZone]failed to parse date" + e);
				}
				List<Award> tempList = timeZone.get(date);
				if (tempList == null) {
					tempList = new ArrayList<Award>();
				}
				if (tempList.contains(award)) {//同一时间点不重复记录，避免之后多次查库
					continue;
				}
				tempList.add(award);
				timeZone.put(date, tempList);
			}
		}

		return timeZone;
	}

	public ActivityService getActivityService() {
		return activityService;
	}

	public void setActivityService(ActivityService activityService) {
		this.activityService = activityService;
	}

	public AwardService getAwardService() {
		return awardService;
	}

	public void setAwardService(AwardService awardService) {
		this.awardService = awardService;
	}

	public WinnerService getWinnerService() {
		return winnerService;
	}

	public void setWinnerService(WinnerService winnerService) {
		this.winnerService = winnerService;
	}

	public BlackListService getBlackListService() {
		return blackListService;
	}

	public void setBlackListService(BlackListService blackListService) {
		this.blackListService = blackListService;
	}
}
